package com.basics.modules.security.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.basics.common.exception.BadRequestException;
import com.basics.common.utils.RedisUtils;
import com.basics.common.utils.SecurityUtils;
import com.basics.logging.aop.log.EnableBasicsLog;
import com.basics.modules.security.anonymity.EnableBasicsAnonymousAccess;
import com.basics.modules.security.config.SecurityProperties;
import com.basics.modules.security.security.TokenProvider;
import com.basics.modules.security.security.vo.AuthUser;
import com.basics.modules.security.security.vo.JwtUser;
import com.basics.modules.security.service.OnlineUserService;
import com.wf.captcha.ArithmeticCaptcha;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**功能描述：授权、根据token获取用户详细信息
 */
@Service
@RestController
@RequestMapping("/auth")
@Api(tags = "系统：系统授权接口")
public class AuthController {

    //验证码过期时间
    @Value("${loginCode.expiration}")
    private Long expiration;
    //后端私钥解密
    @Value("${rsa.private_key}")
    private String privateKey;

    //账号是否多次登录
    @Value("${single.login}")
    private Boolean singleLogin;
    @Resource
    private  SecurityProperties properties;
    @Resource
    private  RedisUtils redisUtils;
    @Resource
    private  UserDetailsService userDetailsService;
    @Resource
    private  OnlineUserService onlineUserService;
    @Resource
    private  TokenProvider tokenProvider;
    @Resource
    private  AuthenticationManagerBuilder authenticationManagerBuilder;





    @EnableBasicsAnonymousAccess
    @ApiOperation("获取验证码")
    @GetMapping("/code")
    public ResponseEntity<Object> getCode(){
        //算术类型 验证码
        ArithmeticCaptcha captcha = new ArithmeticCaptcha(111,36);
        //几位数运算，默认是两位
        captcha.setLen(2);
        //获取验证码计算后最终运行的结果
        String result = captcha.text();
        String uuid = properties.getCodeKey()+ IdUtil.simpleUUID();
        //保存
        redisUtils.set(uuid,result,expiration, TimeUnit.MINUTES);
        //返回验证码信息
        Map<String,Object> imgResult = new HashMap<String,Object>(2){{
            put("img",captcha.toBase64());
            put("uuid",uuid);
        }};

        return ResponseEntity.ok(imgResult);
    }


    @EnableBasicsLog("用户登录")
    @ApiOperation("登录授权")
    @EnableBasicsAnonymousAccess
    @PostMapping(value = "/login")
    public ResponseEntity<Object> login(@Validated @RequestBody AuthUser authUser,
                                        HttpServletRequest request){

        //密码解密
        RSA rsa = new RSA(privateKey,null);
        String password = new String(rsa.decrypt(authUser.getPassword(), KeyType.PrivateKey));

        //通过key查询redis 验证码计算结果
        String code = (String) redisUtils.get(authUser.getUuid());

        //清除验证码
        redisUtils.del(authUser.getUuid());

        //判断验证是否为空
        if(StringUtils.isBlank(code)){
            throw  new BadRequestException("验证码不存在或已过期");
        }

        //判断用户输入的验证码是否正确
        if (StringUtils.isBlank(authUser.getCode()) || !authUser.getCode().equalsIgnoreCase(code)) {
            throw new BadRequestException("验证码错误");
        }

        //根据用户和密码获取token
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(authUser.getUsername(),password);
        //Security调用loadUserByUsername()进行用户存在与否校验返回，若存在则调用内部方法进行密码校验
        //成功认证后AuthenticationManager将返回一个得到完整填充的Authentication实例
        Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
        //建立安全上下文
        SecurityContextHolder.getContext().setAuthentication(authentication);

        //生成令牌
        String token = tokenProvider.createToken(authentication);
        final JwtUser jwtUser = (JwtUser)authentication.getPrincipal();

        //保存在线用户信息
        onlineUserService.save(jwtUser,token,request);
        //返回token与用户信息
        Map<String,Object> authInfo = new HashMap<String,Object>(2){{
            put("token", properties.getTokenStartWith() + token);
            put("user", jwtUser);
        }};

        if(singleLogin){ //踢掉之前已经登录的token
            onlineUserService.checkLoginOnUser(authUser.getUsername(),token);
        }

        return ResponseEntity.ok(authInfo);
    }


    @ApiOperation("获取用户信息")
    @GetMapping("/info")
    public ResponseEntity<Object> getUserInfo(){
        JwtUser jwtUser = (JwtUser)userDetailsService.loadUserByUsername(SecurityUtils.getUsername());
        return ResponseEntity.ok(jwtUser);
    }

    @ApiOperation("退出登录")
    @EnableBasicsAnonymousAccess
    @DeleteMapping(value = "/logout")
    public ResponseEntity<Object> logout(HttpServletRequest request){
        onlineUserService.logout(tokenProvider.getToken(request));
        return new ResponseEntity<>(HttpStatus.OK);
    }

}
